/*	--- 使用Filter --- 

在一个【比较复杂的Web应用程序】中，通常都有很多【URL映射】

对应的，也会有【多个Servlet】来处理【URL】。

我们考察这样一个【论坛Web APP】：

            ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
               /             ┌──────────────┐
            │ ┌─────────────>│ IndexServlet │ │
              │              └──────────────┘
            │ │/signin       ┌──────────────┐ │
              ├─────────────>│SignInServlet │
            │ │              └──────────────┘ │
              │/signout      ┌──────────────┐
┌───────┐   │ ├─────────────>│SignOutServlet│ │
│Browser├─────┤              └──────────────┘
└───────┘   │ │/user/profile ┌──────────────┐ │
              ├─────────────>│ProfileServlet│
            │ │              └──────────────┘ │
              │/user/post    ┌──────────────┐
            │ ├─────────────>│ PostServlet  │ │
              │              └──────────────┘
            │ │/user/reply   ┌──────────────┐ │
              └─────────────>│ ReplyServlet │
            │                └──────────────┘ │
             ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─


各个Servlet设计功能如下：

· IndexServlet：浏览帖子；
· SignInServlet：登录；
· SignOutServlet：登出；
· ProfileServlet：修改用户资料；
· PostServlet：发帖；
· ReplyServlet：回复。


其中，
	ProfileServlet 修改用户资料
	PostServlet 发帖
	ReplyServlet 回复
都需要【用户登录后】才能操作，否则，应当直接跳转到【登录页面】。

我们可以直接把【判断登录的逻辑】写到【这3个Servlet中】

但是，【同样的逻辑】重复3次没有必要，并且，如果【后续】继续加Servlet并且【也需要验证登录时】，还需要继续重复【这个检查逻辑】。

为了把一些【公用逻辑】从【各个Servlet中】抽离出来，【JavaEE的Servlet规范】还提供了【一种Filter组件】，即【过滤器】，

【Filter组件】的作用是，在【HTTP请求】到达【Servlet】之前，可以被【一个或多个Filter】预处理，类似【打印日志、登录检查等】逻辑，完全可以放到【Filter】中。

例如，我们编写一个【最简单的EncodingFilter】，它强制把【输入和输出的编码】设置为【UTF-8】： */
@WebFilter(urlPatterns = '/*')
public class EncodingFilter implements Filter {
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException,ServletException {

		System.out.println("EncodingFilter:doFilter");

		req.setCharacterEncoding("UTF-8");
		resp.setCharacterEncoding("UTF-8");

		chain.doFilter(req, resp);
	}
}


/*
编写Filter时，必须实现【Filter接口】，在【doFilter()方法】内部，要继续【处理请求】，必须【调用chain.doFilter()】。

最后，用【@WebFilter注解】标注【该Filter】需要过滤的【URL】。

这里的【/*】表示【所有路径】。

【添加了Filter】之后，【整个请求】的【处理架构】如下：

            ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
                                   /             ┌──────────────┐
            │                     ┌─────────────>│ IndexServlet │ │
                                  │              └──────────────┘
            │                     │/signin       ┌──────────────┐ │
                                  ├─────────────>│SignInServlet │
            │                     │              └──────────────┘ │
                                  │/signout      ┌──────────────┐
┌───────┐   │   ┌──────────────┐  ├─────────────>│SignOutServlet│ │
│Browser│──────>│EncodingFilter├──┤              └──────────────┘
└───────┘   │   └──────────────┘  │/user/profile ┌──────────────┐ │
                                  ├─────────────>│ProfileServlet│
            │                     │              └──────────────┘ │
                                  │/user/post    ┌──────────────┐
            │                     ├─────────────>│ PostServlet  │ │
                                  │              └──────────────┘
            │                     │/user/reply   ┌──────────────┐ │
                                  └─────────────>│ ReplyServlet │
            │                                    └──────────────┘ │
             ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─


还可以继续添加【其他Filter】，例如【LogFilter】： */
@WebFilter("/*")
public class LogFilter implements Filter {
	public void doFilter(ServletRequest req, SrevletResponse resp, FilterChain chain) throws IOException,ServletException {

		System.out.println("LogFilter: process " + ((HttpServletRequest) req).getRequestURI());

		chain.doFilter(req, resp);
	}
}


/*
【多个Filter】会组成【一个链】，每个请求都被链上的Filter依次处理：

	                                        ┌────────┐
	                                     ┌─>│ServletA│
	                                     │  └────────┘
	    ┌──────────────┐    ┌─────────┐  │  ┌────────┐
	───>│EncodingFilter│───>│LogFilter│──┼─>│ServletB│
	    └──────────────┘    └─────────┘  │  └────────┘
	                                     │  ┌────────┐
	                                     └─>│ServletC│
	                                        └────────┘

Q_1: 有些细心的童鞋会问，有【多个Filter】的时候，【Filter的顺序】如何指定？
Q_2: 多个Filter按【不同顺序处理】会造成【处理结果】不同吗？

A: 答案是【Filter的顺序】确实对【处理的结果】有影响。
   但遗憾的是，【Servlet规范】并没有对【@WebFilter注解】标注的【Filter】规定顺序。
如果一定要给【每个Filter】指定顺序，就必须【在web.xml文件】中,对【这些Filter】再【配置一遍】。

注意到, 【上述的两个Filter】的【过滤路径】都是【/*】，即它们会对【所有请求】进行【过滤】。也可以编写只对【特定路径】进行过滤的【Filter】，例如【AuthFilter】： */
@WebFilter("/user/*")
public class AuthFilter implements Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException {

		System.out.println("AuthFilter: check authentication");

		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse) response;

		if (req.getSession().getAttribute("user") == null) {
			// "未登录", 自动跳转到【登录页】
			System.out.println("AuthFilter: not signin!");

			resp.sendRedirect("/signin");
		} else {
			// 已登录, 继续处理
			chain.doFilter(request, response);
		}
	}
}


/*
注意到【class AuthFilter】只过滤【以/user/开头的路径】，因此：

	· 如果【一个请求路径】类似【/user/profile】，那么它会被【上述3个Filter】依次处理；
	· 如果【一个请求路径】类似【/test】，那么它会被【上述2个Filter, @WebFilter("/*")】依次处理（不会被AuthFilter处理）。


再注意【观察AuthFilter】，当【用户】没有登录时，在【AuthFilter内部】，【直接调用resp.sendRedirect()】发送【重定向】，且【没有继续调用chain.doFilter()】

因此，当【用户没有登录】时，【请求】到达【class AuthFilter】后，不再继续处理.

即【后续的Filter】和【任何Servle】t都【没有机会】处理【该请求】了。

可见，【Filter】可以【有针对性】地拦截/放行【HTTP请求】。

如果【一个Filter】在【当前请求】中生效，但什么都没有做： */
@WebFilter("/*")
public class MyFilter implements Filter {
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException,IOException {
		// TODO
	}
}


/*
那么，【用户】将看到【一个空白页】，因为【请求】没有【继续处理】，【默认响应】是【200 + 空白输出】。

# PS:  如果【Filter】要使【请求】继续【被处理】，就一定要【调用chain.doFilter(request, response)】！


如果我们使用上一节介绍的【MVC模式】，即【一个统一的DispatcherServlet入口】，加上【多个Controller】，这种模式下【Filter】仍然是【正常工作】的。

例如，【一个处理/user/*的Filter】实际上作用于【那些处理/user/开头的Controller方法】之前。


=======================================================

#	----- 使用Filter の 小结 ----- 


1. 【Filter】是一种对【HTTP请求】进行预处理的【组件】，它可以构成【一个处理链】，使得【公共处理代码】能集中到一起；

2. 【Filter】适用于【日志、登录检查、全局设置等】；

3. 设计【合理的URL映射】可以让【Filter链】更清晰。



*/











































